launch 与 launch_ros 的分层架构关系
ros2 launch 一条命令的背后是两个分工明确的包:launch 与 launch_ros。前者是一个与 ROS 无关的通用进程编排框架,后者是在其上构建的 ROS 2 专用扩展层。本文梳理这两层的职责边界——哪些能力是通用的、哪些是 ROS 特有的、它们如何衔接。适合正在编写 launch 文件、想弄清 Node、ExecuteProcess、SetParameter 这些 action 分别来自哪一层的读者。
launch:通用启动框架
仓库结构
launch 仓库位于 src/ros2/launch/,包含以下子包:
| 子包 | 职责 |
|---|---|
launch | 核心框架实现,完全独立于 ROS |
launch_xml | 支持通过 XML 文件定义 launch 描述 |
launch_yaml | 支持通过 YAML 文件定义 launch 描述 |
launch_testing | 提供通用的 launch 测试基础设施 |
launch_pytest | 将 launch 测试接入 pytest 框架 |
launch_testing_ament_cmake | launch_testing 的 ament/CMake 集成 |
核心抽象
LaunchDescription:描述一组待执行的动作。LaunchContext:运行时上下文,用于传递状态和配置。LaunchService:负责执行LaunchDescription。Substitution:支持在运行时动态替换字符串内容。Action:表示一个可执行的操作单元。Condition:控制动作是否执行的条件逻辑。
这套抽象里没有任何 ROS 概念——没有节点、没有话题,只有「动作」「条件」「替换」这些通用的进程编排要素。
内置通用 Actions
这些动作不依赖 ROS,适用于任意进程管理场景:
ExecuteProcess:启动任意外部进程;GroupAction、IncludeLaunchDescription:组织和复用 launch 描述;SetEnvironmentVariable、TimerAction等:环境与时间控制操作。
launch_ros:ROS 2 专用扩展层
依赖关系
launch_ros 仓库位于 src/ros2/launch_ros/,其 package.xml 声明了对 launch 和 rclpy 的运行时依赖:
<exec_depend>launch</exec_depend>
<exec_depend>rclpy</exec_depend> 依赖 rclpy 这一点值得注意:launch 的核心实现语言是 Python,但并不依赖任何 ROS 客户端库;launch_ros 则通过 rclpy 获得 ROS 通信能力,并额外引入 lifecycle_msgs、composition_interfaces 等消息包。
仓库结构
| 子包 | 职责 |
|---|---|
launch_ros | 提供 ROS 特有的 actions、substitutions 和事件处理 |
ros2launch | 实现 ros2 launch 命令行工具 |
launch_testing_ros | 为 ROS 节点测试提供扩展支持 |
新增的 ROS 专用 Actions
Node:启动标准 ROS 2 节点;LifecycleNode:启动支持生命周期管理的节点;ComposableNodeContainer/LoadComposableNodes:管理组件化节点容器及动态加载;PushRosNamespace、SetParameter、SetRemap:分别用于设置命名空间、参数和话题/服务重映射。
可以看到,这些 action 都在管理 ROS 特有的概念:节点生命周期、参数、命名空间、重映射——正是 launch 核心层刻意不涉及的领域。
设计意图与分层逻辑
- 解耦设计:
launch可在无 ROS 环境中独立使用,适用于通用进程编排任务; - 功能聚焦:
launch_ros引入rclpy、lifecycle_msgs、composition_interfaces等 ROS 2 特有依赖,专注于节点生命周期、参数、命名空间等 ROS 概念的管理; - 可测试性:两层均提供对应的测试框架(
launch_testing与launch_testing_ros),支持单元测试与集成测试。
小结
launch 与 launch_ros 的关系是「核心通用、扩展专用」:launch 只提供与 ROS 无关的进程编排原语(动作、条件、替换、事件),launch_ros 在其上叠加节点、生命周期、参数等 ROS 概念,ros2launch 再把这套能力包装成命令行入口。理解这层分界,在排查 launch 行为、决定自定义 action 写在哪一层时都有帮助——通用逻辑放 launch,需要 ROS 通信的放 launch_ros。